
Number.prototype.inRange = function(this: Number, a, b){
	let value = this.valueOf();

	if ([value, a, b].includes(NaN)) return false;

	let [va, vb] = [value - a, value - b].map(v => [-Infinity, Infinity].includes(v) ? v<0 ? -1 : 1 : v);

	return va * vb <= 0;
};

((_global_)=>{
	if(!Reflect.has(_global_, 'mtec')){
		Reflect.set(_global_, 'mtec', {});
		Reflect.set(mtec, '__mtec__', 'Many technologies');
	}

	if(!mtec.number){
		Reflect.set(mtec, 'number', {});
	}
	Reflect.set(mtec.number, '__space_description__', 'This is a mtec subnamespace for number');
})(window ?? globalThis);

Reflect.set(mtec.number, 'PI', Math.PI);
Reflect.set(mtec.number, 'RAD', Math.PI / 180);
Reflect.set(mtec.number, 'DEG', 180 / Math.PI);

mtec.number.inRange = function(num, a, b){
	[num, a, b] = [num, a, b].map(_=>Number(_));
	if([num, a, b].includes(NaN)) return false;

	return num <= Math.max(a, b) && num >= Math.min(a, b);
}

mtec.number.getPrecision = function(num){
	num = Number(num);
	if(isNaN(num) || Number.isInteger(num)) return 0;

	return (num % 1).toString().length - (num>=0 ? 2 : 3);
}

mtec.number.repair = function(num){
	num = Number(num);
	if(isNaN(num)) return 0;
	if(Number.isInteger(num)) return num;

	let str = num.toString();
	if(str.length-str.indexOf('.') < 17) return num;

	let index = str.length-1;
	if(str[index]=='9') while(str[index]=='9') index--;
	else{
		index--;
		while(str[index]=='0') index--;
	}

	let weight = 10 ** (index-str.indexOf('.'));
	return Math.round(num * weight) / weight;
}

mtec.number.random = function(a, b, precision){
	[a, b] = [a, b].map(_=>{
		_ = Number(_);
		return isNaN(_) ? 0 : _;
	});

	let range = b-a;
	if(precision==undefined){
		if(Math.abs(range)==1) precision = 2;
		else if(!Number.isInteger(range)){
			range = mtec.number.repair(range);
			precision = mtec.number.getPrecision(range);
			if(range == 10 ** -precision) precision += 2;
		}else precision = 0;
	}

	let weight = 10 ** precision;

	return mtec.number.repair(a + Math.round(Math.random() * range * weight) / weight);
}

mtec.number.parse = function(value, spare){
	[spare, value] = [spare, value].map(_=>typeof _=='number' ? _ : Number(_));
	return isNaN(value) ? isNaN(spare) ? 0 : spare : value;
}

mtec.number.fixedNum = function(num, place, floor){
	let weight = 10 ** Math.round(mtec.number.parse(place));
	num = num * weight;
	num = floor===true ? Math.floor(num) : floor===false ? Math.ceil(num) : Math.round(num);
	return mtec.number.repair(num / weight);
};

mtec.number.limit = function(num, a, b){
	[num, a, b] = [num, a, b].map(_=>mtec.number.parse(_, 0));
	return Math.max(Math.min(a, b), Math.min(Math.max(a, b), num));
};